package org.example.dao.impl;

import org.example.dao.FullDataMapper;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 访问数据库的工具类，工具类当中的方法都是静态方法
 */
public class DBUtil {
    static Properties properties = new Properties();
    static String url;
    static String userName;
    static String password;

    static {
        InputStream is = null;
        try {
            // 修正类名错误
            is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
            if (is == null) {
                throw new IOException("无法加载数据库配置文件");
            }
            properties.load(is);
            url = properties.getProperty("url");
            userName = properties.getProperty("username");
            password = properties.getProperty("password");
        } catch (IOException e) {
            System.err.println("加载数据库配置文件失败: " + e.getMessage());
            throw new RuntimeException("初始化数据库连接配置失败", e);
        } finally {
            // 确保关闭输入流
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    System.err.println("关闭配置文件输入流失败: " + e.getMessage());
                }
            }
        }
    }

    /**
     * 连接数据库的方法
     * @return 数据库连接对象，如果连接失败返回 null
     */
    public static Connection getConn() {
        try {
            return DriverManager.getConnection(url, userName, password);
        } catch (SQLException e) {
            System.err.println("获取数据库连接失败: " + e.getMessage());
            return null;
        }
    }

    /**
     * 释放资源（关闭连接、Statement 和 ResultSet）
     */
    public static void close(Connection conn, PreparedStatement ps, ResultSet rs) {
        try {
            if (rs != null) rs.close();
            if (ps != null) ps.close();
            if (conn != null) conn.close();
        } catch (SQLException ex) {
            System.err.println("关闭数据库资源失败: " + ex.getMessage());
        }
    }

    /**
     * 关闭连接
     */
    public static void closeConn(Connection conn) {
        try {
            if (conn != null) conn.close();
        } catch (SQLException ex) {
            System.err.println("关闭数据库连接失败: " + ex.getMessage());
        }
    }

    /**
     * 执行 SQL 语句（insert、delete、update）
     * @param sql 被执行的 SQL 语句
     * @param params SQL 语句当中涉及到的占位符对应的值
     * @return 受影响的行数
     */
    public static int executeSql(String sql, Object... params) {
        Connection conn = getConn();
        PreparedStatement ps = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            return ps.executeUpdate();
        } catch (SQLException e) {
            System.err.println("执行 SQL 语句失败: " + e.getMessage());
            return 0;
        } finally {
            close(conn, ps, null);
        }
    }

    /**
     * 执行带有事务的 SQL 语句（insert、delete、update）
     * 此方法不会关闭传入的连接，由调用者负责管理连接
     * @param conn 数据库连接
     * @param sql 被执行的 SQL 语句
     * @param params SQL 语句当中涉及到的占位符对应的值
     * @return 受影响的行数
     */
    public static int executeSqlByTran(Connection conn, String sql, Object... params) {
        PreparedStatement ps = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            return ps.executeUpdate();
        } catch (SQLException e) {
            System.err.println("执行事务 SQL 语句失败: " + e.getMessage());
            return 0;
        } finally {
            // 只关闭 PreparedStatement，不关闭连接
            try {
                if (ps != null) ps.close();
            } catch (SQLException ex) {
                System.err.println("关闭 PreparedStatement 失败: " + ex.getMessage());
            }
        }
    }

    /**
     * 统一的查询方法，返回通用的列表类型
     * @param mapper 数据映射器，用于将 ResultSet 映射为对象
     * @param sql 查询 SQL 语句
     * @param params 查询参数
     * @param <T> 返回对象的类型
     * @return 查询结果列表
     */
    public static <T> List<T> executeQuery(FullDataMapper<T> mapper, String sql, Object... params) {
        List<T> list = new ArrayList<>();
        Connection conn = getConn();
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            rs = ps.executeQuery();
            while (rs.next()) {
                list.add(mapper.map(rs));
            }
        } catch (SQLException ex) {
            System.err.println("执行查询失败: " + ex.getMessage());
        } finally {
            close(conn, ps, rs);
        }
        return list;
    }
}